#ifndef NF_SOCS_SAP_H
#define NF_SOCS_SAP_H
#include <linux/in.h>
#include <linux/in6.h>
#include "socs/comm/constants.h"
#include "socs/comm/types.h"
#include "socs/mod/addr_opt.h"
#include "socs/mod/rbtree.h"

/*********************************/
struct sap {
	socs_addr_t saIP;
	socs_addr_t dIP;
	int  prefix;
	int  is_locallink;
	int  status;
	struct rb_node tree_hook;
};
struct sap_table {
	int family;
	unsigned int locallinkcnt;
	/*just count the sap who's status is SERVING and is_locallink=1*/
	unsigned int sap_num;
	struct rb_root sap_tree;
	// struct sap saps[0];
};

struct addr_in_table {
	int count;
	int prefix_len;
	int set_count_zero_times;
	/*add by chenjq 20160104, due to haven't thought of a good solution to
	  del the ipv6 in saip6-prefix, so when count is equal to 1000, set zero,
	  and other sap also set zero when it's this member is less than this sap */
	struct in6_addr ipv6[0];
};

struct prefix6_table {
	int count;
	struct addr_in_table *addr[0];
};

#define saptb_for_each_sap(pos,saptb) for(pos=0;pos<saptb->sap_num;pos++)
#define SIZEOFSAP  sizeof(struct sap)
#define SIZEOFSAPTB  sizeof(struct sap_table)

bool is_sap(int family, void *address, int *is_nat, struct in_addr *addr_6to4);

bool is_sap_arp(void *address, void *dIP);

bool is_sap6(struct in6_addr *address, struct in6_addr *saIP,
			 struct in6_addr *dIP);
struct sap_table *saptb_get(int family);

int sap_recv_vote(struct hello_packet *hello);

int sap_remove(void *saIP, struct sap_table *saptb);
int saptb_vote(struct sap_table *saptb);
int saptb_vote_for_expire(struct sap_table *saptb, void *expire);
int saptb_vote_for_new(struct sap_table *saptb, void *new);

// void saptb_show(struct sap_table *saptb, int show_locallink);
int saptb_init(char **str_saIP4, int saIP4_size, char **str_saIP6,
			   int saIP6_size);
void saptb_flush(int family);
void saptb_destroy(void);
struct sap *saptb_iterator(struct sap_table *saptb, struct sap *sap);
void saptb_read_lock(int family);
void saptb_read_unlock(int family);

#endif
